package com.zfei.gfb.controller;


import cn.hutool.core.date.DateUtil;
import com.google.common.collect.Lists;
import com.zfei.gfb.api.InboxService;
import com.zfei.gfb.api.StatsService;
import com.zfei.gfb.api.TalkService;
import com.zfei.gfb.api.domain.*;
import com.zfei.gfb.bean.Const;
import com.zfei.gfb.bean.HouseResult;
import com.zfei.gfb.bean.Status;
import com.zfei.gfb.bean.StatusException;
import com.zfei.gfb.core.Auth;
import com.zfei.gfb.core.HttpJson;
import com.zfei.gfb.core.LogResult;
import com.zfei.gfb.dao.GfbHouseApplyMapper;
import com.zfei.gfb.dao.GfbHouseMapper;
import com.zfei.gfb.device.AppContext;
import com.zfei.gfb.model.GfbGuest;
import com.zfei.gfb.model.GfbHouse;
import com.zfei.gfb.model.GfbHouseApply;
import com.zfei.gfb.model.GfbVillager;
import com.zfei.gfb.query.GfbHouseQuery;
import com.zfei.gfb.request.GfbGetRequest;
import com.zfei.gfb.request.GfbHouseAddRequest;
import com.zfei.gfb.request.GfbHouseEditRequest;
import com.zfei.gfb.request.GfbSetRequest;
import com.zfei.gfb.request.h5.CollectRequest;
import com.zfei.gfb.util.Beans;
import com.zfei.gfb.util.Gsons;
import com.zfei.gfb.util.Now;
import com.zfei.gfb.util.TalkUtil;
import com.zfei.gfb.util.gson.Types;
import com.zfei.gfb.vo.GfbHouseApplyVo;
import com.zfei.gfb.vo.GfbHouseListVo;
import com.zfei.gfb.vo.GfbHouseVo;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiResponse;
import io.swagger.annotations.ApiResponses;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import javax.servlet.http.HttpSession;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @author fgh
 * @version 1.0
 */

@Api(tags = "H5房屋接口")
@RestController
@RequestMapping("/h5/house")
public class H5HouseController {

    private static final Logger logger = LoggerFactory.getLogger(H5HouseController.class);

    @Resource
    private GfbHouseMapper gfbHouseMapper;

    @Resource
    private GfbHouseApplyMapper gfbHouseApplyMapper;

    @Resource
    private HttpSession httpSession;

    @Resource
    private TalkService talkService;

    @Resource
    private StatsService statsService;

    @Resource
    private InboxService inboxService;

    @Auth(type = Const.VILLAGER)
    @ApiOperation(value = "房源发布3-2-2-1")
    @ApiResponses({
            @ApiResponse(code = 200, message = "房源发布", response = GfbHouseVo.class),
    })
    @LogResult
    @HttpJson("/my/add")
    public Object add(@RequestBody GfbHouseAddRequest request) {

        request.checkInsertNull();

//        if (request.getUserId() == null) {
//            throw new StatusException(Status.INVALID_ARGUMENT);
//        }
        GfbHouse record = Beans.copy(request, GfbHouse.class);
        record.setImages(Gsons.toJson(request.getImages()));

        GfbVillager villager = (GfbVillager) httpSession.getAttribute(AppContext.SESSION_H5_VILLAGER);

        record.setPutonStatus(Const.STATUS_ON);
        record.setUserId(villager.getId());
        record.setPubTime(Now.millis());
        record.setStatus(Const.HOUSE_STATUS_ING);
        record.setCreateTime(Now.millis());
        record.setUpdateTime(Now.millis());
        record.setCntime(DateUtil.now());

        gfbHouseMapper.insertSelective(record);

        GfbHouseVo vo = Beans.copy(record, GfbHouseVo.class);
        return vo;
    }

    @Auth(type = Const.VILLAGER)
    @ApiOperation(value = "我发布的房屋3-2-2")
    @ApiResponses({
            @ApiResponse(code = 200, message = "我发布的房屋", response = GfbHouseListVo.class),
    })
    @LogResult
    @HttpJson("/my/list")
    public Object listMy(@RequestBody GfbHouseQuery query) {
        query.check().build(Now::millis);
        GfbVillager villager = (GfbVillager) httpSession.getAttribute(AppContext.SESSION_H5_VILLAGER);
        query.setUserId(villager.getId());
        List<GfbHouse> records = gfbHouseMapper.list(query);

        List<GfbHouseVo> vos = new ArrayList<>();
        for (GfbHouse record : records) {
            GfbHouseVo vo = Beans.copy(record, GfbHouseVo.class);
            List<String> images = Gsons.fromJson(record.getImages(), Types.StringListType);
            List<String> checkImages = Gsons.fromJson(record.getCheckImages(), Types.StringListType);

            vo.setImages(images);
            vo.setCheckImages(checkImages);
            vos.add(vo);
        }

        GfbHouseListVo result = new GfbHouseListVo();
        result.setData(vos);
        return vos;

    }

    @Auth(type = Const.VILLAGER)
    @ApiOperation(value = "房源重新编辑3-2-2-2")
    @ApiResponses({
            @ApiResponse(code = 200, message = "房源重新编辑", response = GfbHouseVo.class),
    })
    @LogResult
    @HttpJson("/my/edit")
    public Object edit(@RequestBody GfbHouseEditRequest request) {

        request.checkInsertNull();
        GfbHouse record = gfbHouseMapper.selectByPrimaryKey(request.getId());
        if (record == null) {
            throw new StatusException(Status.NOT_EXIST);
        }

        BeanUtils.copyProperties(request, record);

        record.setImages(Gsons.toJson(request.getImages()));
        record.setPubTime(Now.millis());
        record.setStatus(Const.HOUSE_STATUS_ING);
        record.setUpdateTime(Now.millis());

        gfbHouseMapper.updateByPrimaryKeySelective(record);

        GfbHouseVo vo = Beans.copy(record, GfbHouseVo.class);
        return vo;
    }

    @Auth(type = Const.VILLAGER)
    @ApiOperation(value = "个人中心房源详情3-2-2-2")
    @ApiResponses({
            @ApiResponse(code = 200, message = "个人中心房源详情", response = GfbHouseVo.class),
    })
    @LogResult
    @HttpJson("/my/get")
    public Object getMy(@RequestBody GfbGetRequest request) {
        request.checkGetNull();
        Integer id = request.getId();
        AppContext context = AppContext.getInstance();
        String identifierId = context.getIdentifierId();

        GfbHouse record = gfbHouseMapper.selectByPrimaryKey(id);
        //预约列表
        List<GfbHouseApply> gfbHouseApplyList = gfbHouseApplyMapper.selectByHouseId(id);
        List<GfbHouseApplyVo> gfbHouseApplyVos = gfbHouseApplyList.stream().map(item -> Beans.copy(item, GfbHouseApplyVo.class)).collect(Collectors.toList());

        GfbHouseVo vo = Beans.copy(record, GfbHouseVo.class);
        //房屋图片
        List<String> images = Gsons.fromJson(record.getImages(), Types.StringListType);
        vo.setImages(images);
        //消防图片
        List<String> checkImages = Gsons.fromJson(record.getCheckImages(), Types.StringListType);
        vo.setCheckImages(checkImages);

        vo.setGfbHouseApplyVoList(gfbHouseApplyVos);

        //浏览房屋
        TalkEvent event = this.talkService.getBrowse(identifierId, id.toString());

        if (event == null) {
            this.talkService.createEvent(TalkUtil.buildBrowse(record, identifierId));
        } else {
            this.talkService.recoveryEvent(event.getEventId());
        }

        return vo;
    }

    @Auth(type = Const.VILLAGER)
    @ApiOperation(value = "上/下架3-2-2-2")
    @LogResult
    @HttpJson("/my/set")
    public Object set(@RequestBody GfbSetRequest request) {
        request.checkSetNull(Const::legalTwoStatus);

        Integer id = request.getId();
        Integer status = request.getStatus();

        GfbHouse record = gfbHouseMapper.selectByPrimaryKey(id);
        if (record == null) {
            throw new StatusException(Status.NOT_EXIST);
        }
        record.setPutonStatus(status);
        record.setUpdateTime(Now.millis());
        gfbHouseMapper.updateByPrimaryKeySelective(record);

        return null;
    }


    @ApiOperation(value = "所有房屋列表2-1")
    @ApiResponses({
            @ApiResponse(code = 200, message = "所有房屋列表", response = GfbHouseListVo.class),
    })
    @LogResult
    @HttpJson("/list")
    public Object list(@RequestBody GfbHouseQuery query) {
        query.check().build(Now::millis);
        List<GfbHouse> records = gfbHouseMapper.listH5(query);
        GfbHouseListVo result = new GfbHouseListVo();
        int total = gfbHouseMapper.totalH5(query);
        result.setTotal(total);
        if (total == 0) {
            result.setData(Lists.newArrayList());
            return result;
        }

        List<GfbHouseVo> vos = new ArrayList<>();
        for (GfbHouse record : records) {
            GfbHouseVo vo = Beans.copy(record, GfbHouseVo.class);
            List<String> images = Gsons.fromJson(record.getImages(), Types.StringListType);
            List<String> checkImages = Gsons.fromJson(record.getCheckImages(), Types.StringListType);
            StatsValue browseS = statsService.get(record.getId().toString(), StatsTag.HOUSE_BROWSE_COUNT);
            vo.setBrowseNum(browseS.getNum());
            vo.setImages(images);
            vo.setCheckImages(checkImages);
            vos.add(vo);
        }


        result.setData(vos);
        return result;

    }

    //todo 洌览量
    //todo 收藏量
    @Auth(type = {Const.VILLAGER, Const.GUEST, Const.COMPANY})
    @ApiOperation(value = "房源详情2-1-1")
    @ApiResponses({
            @ApiResponse(code = 200, message = "房源详情", response = GfbHouseVo.class),
    })
    @LogResult
    @HttpJson("/get")
    public Object get(@RequestBody GfbGetRequest request) {
        AppContext context = AppContext.getInstance();
        String identifierId = context.getIdentifierId();
        GfbVillager villager = (GfbVillager) httpSession.getAttribute(AppContext.SESSION_H5_VILLAGER);

        request.checkGetNull();
        Integer id = request.getId();

        GfbHouse record = gfbHouseMapper.selectByPrimaryKey(id);
        if (record == null) {
            throw new StatusException(Status.NOT_EXIST, "房屋不存在或已删除");
        }

        GfbHouseVo vo = Beans.copy(record, GfbHouseVo.class);
        vo.setIsMyHouse(villager != null && record.getUserId().equals(villager.getId()));
        //房屋图片
        List<String> images = Gsons.fromJson(record.getImages(), Types.StringListType);
        vo.setImages(images);
        //消防图片
        List<String> checkImages = Gsons.fromJson(record.getCheckImages(), Types.StringListType);
        vo.setCheckImages(checkImages);

        //浏览房屋
        TalkEvent event = this.talkService.getBrowse(identifierId, id.toString());

        if (event == null) {
            this.talkService.createEvent(TalkUtil.buildBrowse(record, identifierId));
        } else {
            this.talkService.recoveryEvent(event.getEventId());
        }

        StatsValue postStats = new StatsValue(record.getId().toString(), StatsTag.HOUSE_BROWSE_COUNT, 1);
        statsService.inc(postStats);

        StatsValue browseS = statsService.get(record.getId().toString(), StatsTag.HOUSE_BROWSE_COUNT);
        //房源浏览量
        vo.setBrowseNum(browseS == null ? 0 : browseS.getNum());

        StatsValue collectS = statsService.get(record.getId().toString(), StatsTag.HOUSE_COLLECT_COUNT);
        //房源收藏量
        vo.setCollectNum(collectS == null ? 0 : collectS.getNum());

        TalkEvent collect = this.talkService.getCollect(identifierId, record.getId().toString());
        vo.setIsMyCollect(collect != null && collect.notDeleted());


        Integer userId = null;
        Integer type = null;

        if (httpSession.getAttribute(AppContext.SESSION_H5_GUEST) != null) {
            GfbGuest guest = (GfbGuest) httpSession.getAttribute(AppContext.SESSION_H5_GUEST);
            userId = guest.getId();
            type = Const.GUEST;
        }
        Object villagerObj = httpSession.getAttribute(AppContext.SESSION_H5_VILLAGER);
        if (villagerObj != null) {
            GfbVillager villagerObj1 = (GfbVillager) villagerObj;
            userId = villagerObj1.getId();
            type = Const.VILLAGER;
        }
        int size = gfbHouseApplyMapper.selectByHouseIdAndUserIdAndType(record.getId(), userId, type).size();
        vo.setIsMyApply(size > 0);
        return vo;
    }


    @LogResult
    @Auth(type = {Const.VILLAGER, Const.GUEST})
    @HttpJson("/collect")
    @ApiOperation(value = "房源收藏")
    public Object collect(@RequestBody CollectRequest request) {
        AppContext context = AppContext.getInstance();
        String identifierId = context.getIdentifierId();
        long now = Now.millis();

        Integer houseId = request.getHouseId();
        if (houseId == null) {
            throw new StatusException(Status.INVALID_ARGUMENT);
        }
        GfbHouse house = gfbHouseMapper.selectByPrimaryKey(houseId);
        if (house == null) {
            throw new StatusException(Status.NOT_EXIST, "房屋不存在或已删除");
        }
        if (house.getPutonStatus() == Const.STATUS_OFF) {
            throw new StatusException(Status.INVALID_ARGUMENT, "房屋已下架");
        }

        TalkEvent collect = this.talkService.getCollect(identifierId, houseId.toString());
        if (collect != null && collect.getDeleteTime() == 0) {
            throw new StatusException(Status.DUPLICATE);
        }

        if (collect == null) {
            this.talkService.createEvent(TalkUtil.buildCollect(house, identifierId, now));
        } else {
            this.talkService.recoveryEvent(collect.getEventId());
        }

        StatsValue postStats = new StatsValue(house.getId().toString(), StatsTag.HOUSE_COLLECT_COUNT, 1);
        statsService.inc(postStats);
        InboxTuple tuple = new InboxTuple();
        tuple.setName(StatsTag.HOUSE_COLLECT_RECORD + house.getId().toString());
        tuple.setEventId(String.valueOf(Now.millis()));
        tuple.setEventTime(Now.millis());
        inboxService.insert(tuple);

        return null;
    }

    @LogResult
    @Auth(type = {Const.VILLAGER, Const.GUEST})
    @ApiOperation(value = "房源取消收藏")
    @HttpJson("/collect/del")
    public Object collectDel(@RequestBody CollectRequest request) {
        AppContext context = AppContext.getInstance();
        String identifierId = context.getIdentifierId();

        Integer houseId = request.getHouseId();
        if (houseId == null) {
            throw new StatusException(Status.INVALID_ARGUMENT);
        }
        GfbHouse house = gfbHouseMapper.selectByPrimaryKey(houseId);
        if (house == null) {
            throw new StatusException(Status.NOT_EXIST, "房屋不存在或已删除");
        }

        TalkEvent collect = this.talkService.getCollect(identifierId, houseId.toString());
        if (collect == null || collect.getDeleteTime() != 0) {
            throw new StatusException(Status.DUPLICATE);
        }

        this.talkService.deleteEvent(collect.getEventId());

        StatsValue postStats = new StatsValue(house.getId().toString(), StatsTag.HOUSE_COLLECT_COUNT, 1);
        statsService.dec(postStats);
        InboxTuple tuple = new InboxTuple();
        tuple.setName(StatsTag.HOUSE_COLLECT_RECORD + house.getId().toString());
        tuple.setEventId(String.valueOf(Now.millis()));
        tuple.setEventTime(Now.millis());
        inboxService.delete(tuple);

        return null;
    }

    @Auth(type = {Const.VILLAGER, Const.GUEST})
    @LogResult
    @ApiOperation(value = "我收藏的房源")
    @HttpJson("/collect/my")
    @ApiResponses({
            @ApiResponse(code = 200, message = "成功", response = HouseResult.class),
    })
    public Object talkCollectMy(@RequestBody Page query) {
        AppContext context = AppContext.getInstance();
        String identifierId = context.getIdentifierId();

        query.build(Now::millis);

        List<TalkEvent> events = this.talkService.listCollect(identifierId, query);
        if (events.size() == 0) {
            return HouseResult.empty();
        }

        List<Integer> houseIds = events.stream().map(talkEvent -> Integer.parseInt(talkEvent.getParent())).collect(Collectors.toList());

        List<GfbHouse> houses;
        if (houseIds.isEmpty()) {
            houses = new ArrayList<>();
        } else {
            houses = gfbHouseMapper.selectByIds(houseIds);
        }

        return HouseResult.buildHouse(events, houses);
    }

    @Auth(type = {Const.VILLAGER, Const.GUEST})
    @LogResult
    @ApiOperation(value = "我浏览的房源")
    @HttpJson("/browse/my")
    @ApiResponses({
            @ApiResponse(code = 200, message = "成功", response = HouseResult.class),
    })
    public Object browseMy(@RequestBody Page query) {
        AppContext context = AppContext.getInstance();
        String identifierId = context.getIdentifierId();

        query.build(Now::millis);

        List<TalkEvent> events = this.talkService.listBrowse(identifierId, query);
        if (events.size() == 0) {
            return HouseResult.empty();
        }

        //浏览事件去重
        events = events.stream().distinct().collect(Collectors.toList());

        events.forEach(TalkEvent::introspect);


        List<Integer> houseIds = events.stream().map(talkEvent -> Integer.parseInt(talkEvent.getParent())).collect(Collectors.toList());
        List<GfbHouse> houses;
        if (houseIds.isEmpty()) {
            houses = new ArrayList<>();
        } else {
            houses = gfbHouseMapper.selectByIds(houseIds);
        }

        Map<String, List<String>> exhibitionPitemMap = events.stream().collect(Collectors.groupingBy(TalkEvent::getDate, Collectors.mapping(TalkEvent::getEventId, Collectors.toList())));

        HouseResult result = HouseResult.buildHouse(events, houses);

        result.setDateMap(exhibitionPitemMap);

        return result;
    }
}
